/*
 * TransactionBO.java
 *
 * Created on February 28, 2007, 8:58 AM
 *
 */

package edu.byu.isys413.group1E.data;

import edu.byu.isys413.group1E.*;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.ArrayList;

/** Contains information about a transaction, storing the date the transaction
 * occurred, the tax rate, the sub-total, tax, and total amount for the transaction.
 * The TransactionBO also keeps track of the transaction lines that pertain to it,
 * the coupons that are applied to the transaction, as well as the store, employee,
 * customer, and ID of the payment made.
 *
 * If the transaction is a return transaction, there is a variable to store the
 * ID of the original transaction from which the return is made.
 *
 * @author Travis Kulbeth
 */
public class TransactionBO {
    
    private String transID;
    private String transDate;
    private double transTax = 0;
    private double transTaxRate = 0.0625;
    private double transSubTotal = 0;
    private double transTotal = 0;
    private double totalDiscountTaken = 0;        //a variable to store the total discount taken for the customer's convenience
    private ArrayList<CouponBO> CouponList = new ArrayList<CouponBO>();
    private ArrayList<TransLineBO> TxLineList = new ArrayList<TransLineBO>();
    private String originalTransID = null;
    private String transStatus = "Pending";
    private PaymentBO pmt = null;
    private String employeeID;
    private String storeID;
    private String customerID = null;
    boolean alreadyInDB;
    boolean isDirty;
    DecimalFormat fmt = new DecimalFormat();
    
    /** Creates a new instance of TransactionBO */
    TransactionBO(){
        fmt.setMinimumFractionDigits(2);
        fmt.setMaximumFractionDigits(2);
    }
    
    /** Creates a new instance of TransactionBO with an ID*
     *
     * @param transID contains the already existing ID for the transaction to be created.
     */
    TransactionBO(String transID) {
        setTransID(transID);
        setIsDirty(true);
        fmt.setMinimumFractionDigits(2);
        fmt.setMaximumFractionDigits(2);
    }
    
    /** Applies the coupons in the coupon list at this point in the
     * transaction to the respective transaction lines for this transaction.
     */
    public void applyCoupons(){
        this.totalDiscountTaken = 0.0;
        try {
            //if there are coupons to be applied
            this.CouponList = CouponDAO.getInstance().readAllCoup();
            if(!this.CouponList.isEmpty()){
                for(int x=0; x<this.CouponList.size(); x++){                //go through the coupons to see what may apply to a revenue source that has been processed
                    //if there are transactions available for comparison
                    if(!this.TxLineList.isEmpty()){
                        for(int y=0; y<this.TxLineList.size(); y++){        //go through the transactions to see if any coupons apply
                            //check if the coupon applies to the current transaciton line
                            if(this.CouponList.get(x).getRevSrcType().equals(this.TxLineList.get(y).getRevSrc().getType())){
                                setIsDirty(true);
                                
                                this.TxLineList.get(y).setCoupon(this.CouponList.get(x));   //add the coupon to the transaction line to be applied later
                                this.TxLineList.get(y).calcLineAmount();                    //calculate the updated line amount
                                this.totalDiscountTaken += this.TxLineList.get(y).getDiscountTaken();   //add the new discount to the total discounts taken
                            }
                        }//for
                    }else{  //if there are no transactions to process
                        break;
                    }
                }//for
            }
        } catch (DataException ex) {
            ex.printStackTrace();
        } catch (ConnectionPoolException ex) {
            ex.printStackTrace();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
    
    /** Calculates the subTotal (or the total amount of the transaction, including
     * discounts, without the tax calculation.
     */
    public void calcSubTotal(){
        this.transSubTotal = 0.0;
        //if there is content in the list, calculate the subtotal
        if(this.TxLineList != null){
            for(int i=0; i< this.TxLineList.size(); i++){
                this.transSubTotal += this.TxLineList.get(i).getLineAmount();
            }
        }
    }
    
    /** Calculates the Tax for this transaction*/
    public void calcTax(){
        this.transTax = this.transSubTotal * this.transTaxRate;
    }
    
    /** Calculates the total for this transaction, including tax and discounts*/
    public void calcTotal(){
        this.calcTax();
        this.transTotal = this.transSubTotal + this.transTax;
    }
    
    /**
     * Calculates the Change for this transaction according to the payment amount.
     *
     * @param pmtAmount contains the amount of the payment
     * @return change amount
     */
    public double calcChange(double pmtAmount){
        return pmtAmount - this.transTotal;
    }
    
    /** Sets the alreadyInDB variable to indicate that
     * the information contained in this object has been stored in the database
     *
     * @param is contains the alreadyInDB status
     */
    public void setAlreadyInDB(boolean is){
        setIsDirty(true);
        this.alreadyInDB = is;
    }
    
    /** Returns if the information contained in this object has already been stored in the database
     * @return if the object information already exists in the DB
     */
    public boolean isAlreadyInDB() {
        return alreadyInDB;
    }
    
    /** Returns if information has been changed within this object
     * @return if the DB needs to be updated with new info.
     */
    public boolean isIsDirty() {
        return isDirty;
    }
    
    /** Sets the variable isDirty to indicate that some information has been modified or changed
     *in this object
     *
     * @param isDirty indicates whether information has changed
     */
    public void setIsDirty(boolean isDirty) {
        this.isDirty = isDirty;
    }
    
    /** Returns the Transaction ID, which was initially generated by the GUID class
     * @return the transID
     */
    public String getTransID() {
        return transID;
    }
    
    /** Sets the Transaction ID if needed
     * @param transID contains the transactionID to be used for this obejct
     */
    public void setTransID(String transID) {
        setIsDirty(true);
        this.transID = transID;
    }
    
    /** Returns the date the transaction was performed
     * @return the date the transaction was created.
     */
    public String getTransDate() {
        return transDate;
    }
    
    /** sets the date the transaction is performed
     * @param transDate contains the transaction creation date
     */
    public void setTransDate(String transDate) {
        setIsDirty(true);
        this.transDate = transDate;
    }
    
    /** Returns the tax calculated in this transaction
     * @return transTax
     */
    public double getTransTax() {
        return transTax;
    }
    
    /** sets the value for the tax calculated in this transaction
     * @param transTax contains the tax rate for this transaction
     */
    public void setTransTax(double transTax) {
        setIsDirty(true);
        this.transTax = transTax;
    }
    
    /** returns the subTotal of this transaction
     *@return transSubTotal
     */
    public double getTransSubTotal() {
        return transSubTotal;
    }
    
    /** sets the subtotal amount calculated in this transaction
     *@param transSubTotal contains the subtotal for this transaction
     */
    public void setTransSubTotal(double transSubTotal) {
        setIsDirty(true);
        this.transSubTotal = transSubTotal;
    }
    
    /** Returns the transaction total calculated in this transaction
     * @return transTotal
     */
    public double getTransTotal() {
        return transTotal;
    }
    
    /** Sets the transaction total calculated in this transaction
     * @param transTotal contains the total for this transaction
     */
    public void setTransTotal(double transTotal) {
        setIsDirty(true);
        this.transTotal = transTotal;
    }
    
    /** Returns the list of Coupons that were applied in this transaction.
     *This coupon list is used to determine possible discounts on the revenue
     *sources contained in the TransLineBO list
     *
     *@return list of coupons for this transaction
     */
    public ArrayList<CouponBO> getCouponList() {
        return CouponList;
    }
    
    /** A method to set a whole new list to the couponList containing
     *coupons to be used in calculating discounts for this transaction.
     *
     * @param CouponList contains a list of coupons to be applied in this transaction
     */
    public void setCouponList(ArrayList<CouponBO> CouponList) {
        setIsDirty(true);
        this.CouponList = CouponList;
    }
    
    /** Adds a CouponBO to the Coupon list to be used in calculating
     *discounts.
     *
     *@param coup contains a coupon to be added to the list
     */
    public void addCoupon(CouponBO coup){
        setIsDirty(true);
        this.CouponList.add(coup);
    }
    
    /** Returns the list of TransLineBOs (transaction lines) pertaining to
     *this transaction.
     *
     *@return List of all transaction lines for this transaction
     */
    public ArrayList<TransLineBO> getTxLineList(){
        if(TxLineList.isEmpty()){
            try {
                this.setTxLineList(TransLineDAO.getInstance().readByTransaction(this.getTransID()));
            } catch (ConnectionPoolException ex) {
                ex.printStackTrace();
            } catch (DataException ex) {
                ex.printStackTrace();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
        return this.TxLineList;
    }
    
    /** A method to set a whole new list to the TxLineList containing the
     *transaction lines pertaining to this transaction
     *
     *@param TxLineList contains Transaction Lines which are part of this transaction
     */
    public void setTxLineList(ArrayList<TransLineBO> TxLineList) {
        setIsDirty(true);
        this.TxLineList = TxLineList;
    }
    
    /** Adds a TransLineBO to the Transaction Line list to be used in calculating
     *discounts.
     *
     *@param txLine contains a new transaction line object for this transaction
     */
    public void addTxLine(TransLineBO txLine){
        setIsDirty(true);
        txLine.calcLineAmount();
        this.TxLineList.add(txLine);
    }
    
    /** Returns the transID for the original transaction performed if this
     *transaction is a return.
     *
     * @return transaction ID of the original transaction
     */
    public String getOriginalTransID() {
        return originalTransID;
    }
    
    /** If this transaction is for a return, this method
     *sets the variable containing the transID of the original transaction
     *that the return refers to.
     *
     * @param originalTransID contains the id for the original transaction to which
     *this one refers.
     */
    public void setOriginalTransID(String originalTransID) {
        setIsDirty(true);
        this.originalTransID = originalTransID;
    }
    
    /** Returns the total Discount taken for this transaction
     *@return the total discounts taken by this transaction
     */
    public double getTotalDiscountTaken() {
        return totalDiscountTaken;
    }
    
    /** Sets the total discount taken for this transaction
     *@param totalDiscountTaken contains the total amount of discounts
     *that were applied to this transaction
     */
    public void setTotalDiscountTaken(double totalDiscountTaken) {
        setIsDirty(true);
        this.totalDiscountTaken = totalDiscountTaken;
    }
    
    /** Returns the tax rate used for this transaction
     *@return the tax rate used in this transaction
     */
    public double getTransTaxRate() {
        return transTaxRate;
    }
    
    /** Sets the transaction tax rate
     * @param transTaxRate sets the tax rate to be used in this transaction
     */
    public void setTransTaxRate(double transTaxRate) {
        this.setIsDirty(true);
        this.transTaxRate = transTaxRate;
    }
    
    /** Returns the transaction status
     * @return transStatus
     */
    public String getTransStatus() {
        return transStatus;
    }
    
    /** Sets the transaction status
     *
     * @param transStatus contains the status of this transaction
     */
    public void setTransStatus(String transStatus) {
        this.setIsDirty(true);
        this.transStatus = transStatus;
    }
    
    /** Returns the payment object for this transaction
     *
     * @return PaymentBO
     */
    public PaymentBO getPmt() {
        return pmt;
    }
    
    /** Sets the payment object for this transaction
     * @param pmt contains the payment object for this transaction
     */
    public void setPmt(PaymentBO pmt) {
        this.setIsDirty(true);
        if(pmt != null){
            this.setTransStatus("Complete");        //set the transaction status to complete since payment has been received
        }
        this.pmt = pmt;
    }
    
    /** Sets the session information for this object
     *
     *@param s contains the session information
     */
    public void setSession(Session s){
        this.setEmployeeID(s.getEmployee().getEmployeeID());
        this.setStoreID(s.getStore().getStoreID());
    }
    
    /** Return the id of the employee who performed this transaction
     *@return employeeID
     */
    public String getEmployeeID() {
        return employeeID;
    }
    
    /**
     * Returns the employee object upon demand
     *
     * @return EmployeeBO for the employeeID
     * @throws java.lang.Exception for any errors encountered when reading an Employee
     */
    public EmployeeBO getEmployee() throws Exception{
        return EmployeeDAO.getInstance().read(this.employeeID);
    }
    
    /** Sets the employee ID for this transaction
     *
     *@param employeeID contains the employeeID for this transaction
     */
    public void setEmployeeID(String employeeID) {
        this.setIsDirty(true);
        this.employeeID = employeeID;
    }
    
    /** Returns the id of the store where this transaction took place
     *
     *@return storeID
     */
    public String getStoreID() {
        return storeID;
    }
    
    /** Returns the store object of where this transaction took place upon demand\
     *
     * @return storeBO for the storeID
     */
    public StoreBO getStore() {
        StoreBO store = null;
        try {
            store = StoreDAO.getInstance().read(storeID);
        } catch (DataException ex) {
            ex.printStackTrace();
        } catch (ConnectionPoolException ex) {
            ex.printStackTrace();
        }
        return store;
    }
    
    /** Sets the store ID for this transaction
     *
     *@param storeID contains storeID for Store
     */
    public void setStoreID(String storeID) {
        this.setIsDirty(true);
        this.storeID = storeID;
    }
    
    /**
     * Returns the Customer for this transaction when requested
     *
     * @throws Exception for any error encountered in retrieving the customer
     * @return CustomerBO for the customerID
     */
    public CustomerBO getCustomer() throws Exception{
        return CustomerDAO.getInstance().read(this.customerID);
    }
    
    /** Returns the customer ID for this transaction
     *@return customerID
     */
    public String getCustomerID(){
        return this.customerID;
    }
    
    /** Sets the CustomerID for this transaction
     *@param customerID contains the id for this transaction's customer
     */
    public void setCustomerID(String customerID) {
        this.setIsDirty(true);
        this.customerID = customerID;
    }
}
